#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include "IList.h"


#define true 1
#define false 0

int gc_enable;
pthread_t gc;

void* _collectTheGarbage(void *queue){
	LIST *q = (LIST*)queue;
    NODE* tmp;
    while(gc_enable){
        while((q->first != q->head_p) && (q->first->next != q->head_p)){
            tmp = q->first;
            /*if(tmp->value != NULL) free(tmp->value);*/
            q->first = q->first->next;
            free(tmp);
        }
    }
    pthread_exit((void*)0);
}

void collectTheGarbage(LIST* q, pthread_t* t){
    gc_enable = true;
    pthread_create(t, NULL, _collectTheGarbage, (void*)q);
}



void stopCollectTheGarbage(LIST* q){
    gc_enable = false;
}

int pointer_compare(NODE* p, NODE* q){
   if(p != q) return false;
   if(p->mark != q->mark) return false;
   return true;
}

void init_list(LIST *q)
{   
    
    q->head_p = (NODE*) malloc(sizeof(NODE));
    q->tail = q->first = q->head_p;
    q->head_p->value = -1;
    q->head_p->next = NULL;
    gc_enable = false;

    collectTheGarbage(q,&gc);
}


int count(LIST *q)
{
	NODE* tmp = q->first;
    int count = 0;
    while(tmp != NULL){
        count++;
        tmp = tmp->next;
    }
    return count;
}


void ps_insert(LIST *q, const int element)
{   
	NODE* tail,*next;
    NODE* node;
    node = (NODE*)malloc(sizeof(NODE));
    node->value = element;
    node->next = NULL;
    node->mark = time(0);
    while(true)
    {
        tail = q->tail;
        next = tail->next;
        if(pointer_compare(tail,q->tail)){
            if(next == NULL){
                if(__sync_bool_compare_and_swap(&(tail->next), next, node))
                    break;
            }
            else{
                __sync_bool_compare_and_swap(&(q->tail), tail, next);
            }
        }
    }
    __sync_bool_compare_and_swap(&(q->tail), tail, node);
}


//Boolean return
int ps_remove(LIST* q, const int v)
{
	int data;
    while(1){
    	NODE* head = q->head_p;
    	NODE* next = head->next;
    	NODE* tail;
        if(head == q->head_p){
            if(next == NULL)
                return -1;
            else{
                data = next->value;
                if(__sync_bool_compare_and_swap(&(q->head_p),head,next)){
                    tail = q->tail;
                    //Special case when Head and Tail are crossed
                    if(head == tail) __sync_bool_compare_and_swap(&(q->tail),tail,next);
                }
            }
        }
    }
    return data;
}

void clear(LIST *q)
{
	void* status;
	stopCollectTheGarbage(q);
	pthread_join(gc, &status);

	NODE* tmp;
    while (q->first->next != NULL) {
        tmp = q->first;
        /*if(tmp->value != NULL)free(tmp->value);*/
        q->first = q->first->next;
        free(tmp);
    }
}
